#pragma once
#include <vector>
#include <list>
#include <string>

void execute(std::vector<char> &mem);
long long deal(long long PC);
bool judgeCode(char code);
void ALU(long long ALUA, long long ALUB, char fun);
bool cond(char ifun);
void selectPC();
void Sel_FwdA();
void FwdB();
void control();
void refresh();

class Fetch
{
public:
	Fetch(): predPC(0), stall(0) { }
	void run();
	void clear() { predPC = 0; }
	char stall;
	long long predPC;
};

class Decode
{
public:
	Decode(): icode(1), ifun(0), rA(0xf), rB(0xf), valC(0), valP(0), stat(1), stall(0), bubble(0) { }
	void run();
	void clear() { icode =1 , ifun = 0, rA = 0xf, rB = 0xf, valC = 0, valP = 0, stat = 1, stall = 0, bubble = 0; }
	char icode, ifun, rA, rB, stat, stall, bubble;
	long long valC, valP;
};

class Execute
{
public:
	Execute(): icode(1), ifun(0), valC(0), valA(0), valB(0), dstE(0xf), dstM(0xf), srcA(0xf), srcB(0xf), stat(1), bubble(0) { }
	void clear() { icode = 1, ifun = 0, valC = 0, valA = 0, valB = 0, dstE = 0xf, dstM = 0xf, srcA = 0xf, srcB = 0xf, stat = 1, bubble = 0; }
	void run();
	char icode, ifun, stat, bubble;
	long long valC, valA, valB, dstE, dstM, srcA, srcB;
};

class Memory
{
public:
	Memory(): icode(1), Cnd(0), valE(0), valA(0), dstE(0xf), dstM(0xf), stat(1), bubble(0) { }
	void clear() { icode = 1, Cnd = 0, valE = 0, valA = 0, dstE = 0xf, dstM = 0xf, stat = 1, bubble = 0; }
	void run();
	bool Cnd;
	char icode, stat, bubble;
	long long valE, valA, dstE, dstM;
};

class Write
{
public:
	void run();
	Write() : icode(1), valE(0), valM(0), dstE(0xf), dstM(0xf), stat(1), stall(0) { }
	void clear() { icode = 1, valE = 0, valM = 0, dstE = 0xf, dstM = 0xf, stat = 1, stall = 0; }
	char icode, stat, stall;
	long long valE, valM, dstE, dstM;
};

class Condition
{
public:
	Condition(): ZF(0), SF(0), OF(0), PC(0), Stat(1) { }
	bool ZF, SF, OF;
	long long  PC;
	char Stat;
	static const char AOK = 1;		// AOK: 正常操作
	static const char HLT = 2;		// HLT: 执行 halt 指令
	static const char ADR = 3;		// ADR: 非法地址
	static const char INS = 4;		// INS: 非法指令
	static const char WAITCLK = 3;	// WAITCLK: 更新 Cache 等待时钟数
};

class StoreChange
{
public:
	void print();
	long long regIn[15], regOut[15];
	std::vector<long long> memAddr, memIn, memOut;
};

class CacheLine
{
	public:
		CacheLine(): usage(0), vld(0), dirty(0) { }
		CacheLine(int size): usage(0), vld(0), dirty(0), block(size, 0) { }
		bool writeBack() const { return dirty; }
		bool valid() const { return vld; }
		int getTag() const { return tag; }
		static void setMemory(std::vector<char> *ptr) { m = ptr; }
		char readByte(int offset);
		void writeByte(int offset, char data);
		void load(int inTag, long long addr);
		int usage;	// 记录最后被使用的时钟数
		void print();
	private:
		std::vector<char> block;
		static std::vector<char> *m;
		long long ad;	// Block 中数据对应内存块的起始地址
		int tag;
		bool vld, dirty;// 是否有效及是否写入过 Block
};

class CacheSet
{
	public:
		CacheSet(): valid(0) { }
		CacheSet(int SetSize, int BlockSize): dt(SetSize, CacheLine(BlockSize)), valid(0) { }
		char read(long long addr, int tag, int offset);
		void write(long long addr, int tag, int offset, char data);
		std::list<CacheLine>::iterator miss(long long addr, int tag);
		void print();
	private:
		std::list<CacheLine> dt;
		int valid;	// 有效 Block 数目
};

class Cache
{
	public:
		Cache(): t(0), s(0), b(0) { }
		Cache(int t, int s, int b, int SetSize): dt(1 << s, CacheSet(SetSize, 1 << b)), t(t), s(s), b(b)
		{
			mask1 = (1ll << t) - 1;
			mask2 = (1ll << s) - 1;
			mask3 = (1ll << b) - 1;
		}
		CacheSet &operator[](int index) { return dt[index]; }
		char read(long long addr);
		void write(long long addr, char data);
		static const int WAITTIME = 1;		// 从内存拷贝数据到 Cache 中所需时钟数
		void print();
	private:
		void getAddr(long long addr, int &tag, int &index, int &offset);
		std::vector<CacheSet> dt;
		int t, s, b;	// 地址解析 t位标记 s位组索引 b位块偏移
		int mask1, mask2, mask3;
};
